package com.gict.antifraudback.aspect;

import com.alibaba.fastjson.JSON;
import com.gict.antifraudback.entity.LogExcp;
import com.gict.antifraudback.entity.LogExcpDetail;
import com.gict.antifraudback.service.ILogExcpDetailService;
import com.gict.antifraudback.service.ILogExcpService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 记录到错误日志表
 */
@Slf4j
@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private ILogExcpService excLogService;
    @Autowired
    private ILogExcpDetailService logExcpDetailService;

    @Pointcut("execution(* com.gict.antifraudback.controller..*.*(..))")
    public void excLogPointCut() {

    }

    @AfterThrowing(value = "excLogPointCut()", throwing = "throwable")
    public void saveOperationError(JoinPoint joinPoint, Throwable throwable) throws Throwable{
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        LogExcp logExcp = new LogExcp();
        try {
            // 请求的方法名
            Signature signature = joinPoint.getSignature();
            logExcp.setExcName(throwable.getClass().getName());
            logExcp.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
            logExcp.setUri(request.getRequestURI());
            logExcp.setIp(request.getRemoteAddr());
            Map<String, String> requestParam = convertMap(request.getParameterMap());
            // 异常信息
            logExcp.setMessage(stackTraceToString(throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace()));
            excLogService.save(logExcp);

            LogExcpDetail logExcpDetail = new LogExcpDetail();
            logExcpDetail.setLogExcpId(logExcp.getId());
            logExcpDetail.setRequestParam(JSON.toJSONString(requestParam));
            logExcpDetailService.save(logExcpDetail);
        } catch (Exception e) {
            // 此处需要重新抛出异常
            e.printStackTrace();
            throw e;
        }
    }


    /**
     * 转换request 请求参数
     *
     * @param paramMap request获取的参数数组
     */
    public Map<String, String> convertMap(Map<String, String[]> paramMap) {
        Map<String, String> rtnMap = new HashMap<String, String>();
        for (String key : paramMap.keySet()) {
            rtnMap.put(key, paramMap.get(key)[0]);
        }
        return rtnMap;
    }


    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "\n");
        }
        return exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
    }
}
